﻿
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
using Labthink.PCSoft.UniversalHost4.Utility;
using Point = System.Windows.Point;

namespace Chart
{
    public class Line
    {
        public int Id { get; set; }
        public int AppendId { get; set; }
        public const double PointDia = 4;
        #region 控制
        /// <summary>
        /// 是否独占Y轴
        /// </summary>
        public bool IsMonopolizeY { get; set; }
        /// <summary>
        /// 是否画数据点
        /// </summary>
        public bool IsDrawPoint { get; set; }

        /// <summary>
        /// 父控件宽度
        /// </summary>
        public double ParentW { get; set; }

        /// <summary>
        /// 父控件高度
        /// </summary>
        public double ParentH { get; set; }

        /// <summary>
        /// 最大值
        /// </summary>
        public double MaxX { get; set; }

        /// <summary>
        /// 最小值
        /// </summary>
        public double MinX { get; set; }

        public Axis Y { get; set; }

        public bool IsShow { get; set; }
        private int? _index;
        #endregion

        #region 显示


        /// <summary>
        /// 显示的线
        /// </summary>
        public Path LinePath { get; }
        /// <summary>
        /// Y轴刻度值
        /// </summary>
        public List<TextBlock> YScales { get; set; }
        /// <summary>
        /// 图例
        /// </summary>
        public UcLegend Legend { get; }

        #endregion

        #region 操作
        /// <summary>
        /// 显示、隐藏操作按钮
        /// </summary>
        public TextBlock LineLabel { get; }

        public event EventHandler<PointEventArgs> OnPointAddHandler;
        public event EventHandler<EventArgs> OnLineLabelClickHandler;
        public event EventHandler<EventArgs> OnLineYAxisChangedHandler;
        #endregion

        #region 数据

        private PathFigure _line;

        private readonly List<Point> _lineDatas;
        private readonly List<Ellipse> _linePoints;

        public List<Ellipse> LinePoints => _linePoints;
        public PathFigure LineCore => _line;

        public List<Point> LineDatas => _lineDatas;
        #endregion

        public Line(LineStyleManager style, bool showPoint, string name, string unit, int precision, int? index = null)
        {
            IsDrawPoint = showPoint;
            Y = new Axis
            {
                Text = name,
                Unit = unit,
                Precision = precision
            };
            MaxX = double.MinValue;
            Y.OriginMax = Y.Max = Math.Pow(10, -precision) * 10.0;
            MinX = 0;
            Y.OriginMin = Y.Min = 0;
            _lineDatas = new List<Point>();
            if (IsDrawPoint) _linePoints = new List<Ellipse>();
            LinePath = new Path { StrokeThickness = 1 };
            _line = new PathFigure();
            style.Brush(LinePath);
            Legend = new UcLegend { Margin = new Thickness(5, 0, 5, 0) };
            Legend.Init(LinePath.Stroke, name + (string.IsNullOrEmpty(unit) ? "" : $"({unit})"), LinePath.StrokeDashArray);
            LineLabel = new TextBlock { Background = Brushes.Transparent, Margin = new Thickness(2), FontSize = 16, Foreground =Brushes.Black };
            //LineLabel.Visibility = Visibility.Visible;
            //LineLabel.Text = "123";
            //Canvas.SetLeft(LineLabel, 94);
            //Canvas.SetTop(LineLabel, 470);
            YScales = new List<TextBlock>();
            //LineLabel.MouseLeftButtonUp += LineLabel_Click;
        }

        public Line Copy(LineStyleManager style, int index, int? id)
        {
            var line = new Line(style, IsDrawPoint, Y.Text, Y.Unit, Y.Precision, index)
            {
                Id = Id,
                IsMonopolizeY = true,
                YScales = YScales

            };
            line.Y.Min = Y.Min;
            line.Y.Max = Y.Min;
            line.Y.OriginMin = Y.OriginMin;
            line.Y.OriginMax = Y.OriginMax;
            line.Y.Type = Y.Type;
            line.MaxX = MaxX;
            line.MinX = MinX;
            IsMonopolizeY = false;
            AppendId = Id;

            if (id.HasValue)
            {
                line.Id = id.Value;
                AppendId = id.Value;
            }
            else
            {
                Id = -Id;
            }
            return line;
        }


        public void Add(double x, double y)
        {
            //转换成曲线坐标
            var ischange = false;
            if (Y.Min > y)
            {
                ischange = true;
                Y.Min = _calcAxis(y);
            }
            if (Y.Max < y)
            {
                ischange = true;
                Y.Max = _calcAxis(y);
            }

            if (ischange)
            {
                //Y坐标轴极值改变，刷新Y轴刻度和历史曲线
                FlashY(Y.Max, Y.Min);
                OnLineYAxisChangedHandler?.Invoke(this, new EventArgs());
            }
            var p = _data2Point(x, y);
            if (_lineDatas.Count == 0)
            {
                _line.StartPoint = p;
                //_line.Segments.Add(new LineSegment(p, true));
                var lines = new PathGeometry();
                lines.Figures.Add(_line);
                LinePath.Data = lines;
            }
            _line.Segments.Add(new LineSegment(p, true));

            if (IsDrawPoint)
            {
                var data = (Y.Type == 2 ? y.ScientificNotation(Y.Precision) : y.Round(Y.Precision));
                var ell = new Ellipse
                {
                    Width = PointDia,
                    Height = PointDia,
                    Fill = LinePath.Stroke,
                    StrokeThickness = 0,
                    Tag = data,
                    ToolTip = new ToolTip
                    {
                        Content = data + ""

                    },
                    Visibility = IsShow ? Visibility.Visible : Visibility.Collapsed
                };

                _linePoints.Add(ell);
                Canvas.SetLeft(ell, p.X - PointDia / 2);
                Canvas.SetTop(ell, p.Y - PointDia / 2);
                OnPointAddHandler?.Invoke(this, new PointEventArgs
                {
                    Point = ell
                });
            }

            _lineDatas.Add(new Point(x, y));
        }

        public void FlashX(double max, double min)
        {
            MaxX = max;
            MinX = min;
            var index = 0;
            foreach (var s in _line.Segments)
            {
                var ls = s as LineSegment;
                if (ls != null)
                {
                    var p = _lineDatas[index];
                    var x = (p.X - min) * ParentW / (max - min);
                    var y = ls.Point.Y;
                    ls.Point = new Point(x, y);
                    if (index == 0) _line.StartPoint = ls.Point;
                    if (IsDrawPoint)
                    {
                        var e = _linePoints[index];
                        Canvas.SetLeft(e, x - PointDia / 2);
                    }
                }

                index++;
            }
        }

        public void FlashY(double max, double min)
        {
            var index = 0;
            var ys = (max - min) / (YScales.Count - 1);
            for (int i = 0; i < YScales.Count; i++)
            {
                YScales[i].Text = (max - i * ys).Round(Y.Precision);
                if (Y.Type == 2)
                {
                    //科学计数
                    YScales[i].Text = (max - i * ys).ScientificNotation(Y.Precision);
                }
            }
            foreach (var s in _line.Segments)
            {
                var ls = s as LineSegment;
                if (ls != null)
                {
                    var p = _lineDatas[index];
                    var x = ls.Point.X;
                    var y = ParentH - (p.Y - min) * ParentH / (max - min);
                    ls.Point = new Point(x, y);
                    if (index == 0) _line.StartPoint = ls.Point;
                    if (IsDrawPoint)
                    {
                        var e = _linePoints[index];
                        Canvas.SetTop(e, y - PointDia / 2);
                    }
                }

                index++;
            }
        }

        public void Clear()
        {
            //清空数据
            LinePath.Data = null;
            _line = new PathFigure();
            _lineDatas.Clear();
            if (IsDrawPoint)
            {
                _linePoints.Clear();
            }

            //重置坐标
            Y.Max = Y.OriginMax;
            Y.Min = Y.OriginMin;
            var ys = (Y.Max - Y.Min) / (YScales.Count - 1);
            for (int i = 0; i < YScales.Count; i++)
            {
                YScales[i].Text = (Y.Max - i * ys).Round(Y.Precision);
                if (Y.Type == 2)
                {
                    //科学计数
                    YScales[i].Text = (Y.Max - i * ys).ScientificNotation(Y.Precision);
                }
            }
            if (_index.HasValue)
            {
                LineLabel.Text = Y.Text + "1";
            }
            
            //LineLabel.MouseLeftButtonUp -= LineLabel_Click;
        }

        public void Show()
        {
            IsShow = true;
            LinePath.Visibility = Visibility.Visible;
            Legend.Visibility = Visibility.Visible;
            foreach (var tb in YScales)
            {
                tb.Visibility = Visibility.Visible;
            }
            if (IsDrawPoint)
            {
                foreach (var elli in _linePoints)
                {
                    elli.Visibility = Visibility.Visible;
                }
            }

            LineLabel.Visibility = Visibility.Visible;
        }

        public void Hide()
        {
            IsShow = false;
            LinePath.Visibility = Visibility.Collapsed;
            Legend.Visibility = Visibility.Collapsed;
            foreach (var tb in YScales)
            {
                tb.Visibility = Visibility.Collapsed;
            }
            if (IsDrawPoint)
            {
                foreach (var elli in _linePoints)
                {
                    elli.Visibility = Visibility.Collapsed;
                }
            }

            LineLabel.Visibility = Visibility.Collapsed;
        }

        #region 内部方法
        private void LineLabel_Click(object sender, RoutedEventArgs e)
        {
            OnLineLabelClickHandler?.Invoke(this, new EventArgs());
        }

        private double _calcAxis(double v)
        {
            var r = v;
            if (Y.Type == 1)
            {
                r = Math.Ceiling(r / 10) * 10;
            }
            else
            {
                r = v * (1.2 + ((double)Id % 10) / 20);
            }

            return r;
        }

        private Point _data2Point(double x, double y)
        {
            var px = (x - MinX) * ParentW / (MaxX - MinX);
            var py = ParentH - (y - Y.Min) * ParentH / (Y.Max - Y.Min);
            return new Point(px, py);
        }

        #endregion
    }

    public class PointEventArgs : EventArgs
    {
        public Ellipse Point { get; set; }
    }
}
